"""
Global server configuration management for MCPM v2.0

This module manages the global server registry where all servers are stored centrally.
Profiles tag servers but don't own them - servers exist globally.
"""

import json
import logging
import os
from typing import Dict, List, Optional

from pydantic import TypeAdapter

from sys_intd.constant import DEFAULT_LOCAL_CONFIG_PATH, DEFAULT_LOCAL_MCPS_CONFIG_PATH, PROJECT_MCP_CENTER_PATH
from sys_intd.schema import McpCenter, ServerConfig, MCPInfo

logger = logging.getLogger(__name__)


class McpServerManager:
    """Manages Mcp Server.
    """

    def __init__(
            self, config_path: str = DEFAULT_LOCAL_CONFIG_PATH, mcps_path: str = DEFAULT_LOCAL_MCPS_CONFIG_PATH,
            mcp_center_path: str = PROJECT_MCP_CENTER_PATH
    ):
        self.config_path = os.path.expanduser(config_path)
        self.config_dir = os.path.dirname(self.config_path)

        self.mcps_path = os.path.expanduser(mcps_path)
        self.mcp_center_path = os.path.expanduser(mcp_center_path)
        self.mcp_info_path = os.path.join(self.mcp_center_path, "mcp_config")

        self._servers: Dict[str, ServerConfig] = self._load_servers()
        self._ensure_dirs()
        self.mcp_center = McpCenter()

    def _ensure_dirs(self) -> None:
        """Ensure all configuration directories exist"""
        os.makedirs(self.config_dir, exist_ok=True)
        os.makedirs(self.mcps_path, exist_ok=True)
        os.makedirs(self.mcp_center_path, exist_ok=True)

    def get_mcp_center_service_path(self) -> str:
        return os.path.join(self.mcp_center_path, self.mcp_center.service)

    def get_mcp_center_mcps_config_path(self) -> str:
        return os.path.join(self.mcp_center_path, self.mcp_center.mcp_config)

    def get_mcp_center_servers_path(self) -> str:
        return os.path.join(self.mcp_center_path, self.mcp_center.servers)

    def get_mcp_metadata(self, server_name: str) -> Dict:
        data = {}
        for mcp_config in os.listdir(self.mcp_info_path):
            if server_name in mcp_config:
                mcp_config_json = os.path.join(self.mcp_info_path, mcp_config, "config.json")
                with open(mcp_config_json, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    break

        return data

    def _load_servers(self) -> Dict[str, ServerConfig]:
        """Load servers from the global configuration file."""
        if not os.path.exists(self.config_path):
            return {}

        try:
            with open(self.config_path, "r", encoding="utf-8") as f:
                servers_data = json.load(f) or {}
        except json.JSONDecodeError as e:
            logger.error(f"Error loading global servers from {self.config_path}: {e}")
            return {}

        servers = {}
        for name, config_data in servers_data.items():
            try:
                servers[name] = TypeAdapter(ServerConfig).validate_python(config_data)
            except Exception as e:
                logger.error(f"Error loading server {name}: {e}")
                continue

        return servers

    def _save_servers(self) -> None:
        """Save servers to the global configuration file."""
        self._ensure_dirs()
        servers_data = {name: config.model_dump() for name, config in self._servers.items()}

        with open(self.config_path, "w", encoding="utf-8") as f:
            json.dump(servers_data, f, indent=2)

    def add_server(self, server_config: ServerConfig, force: bool = False) -> bool:
        """Add a server to the global configuration.

        Args:
            server_config: The server configuration to add
            force: Whether to overwrite existing server

        Returns:
            bool: Success or failure
        """
        if server_config.name in self._servers and not force:
            logger.warning(f"Server '{server_config.name}' already exists")
            return False

        self._servers[server_config.name] = server_config
        self._save_servers()
        return True

    def remove_server(self, server_name: str) -> bool:
        """Remove a server from the global configuration.

        Args:
            server_name: Name of the server to remove

        Returns:
            bool: Success or failure
        """
        if server_name not in self._servers:
            logger.warning(f"Server '{server_name}' not found")
            return False

        del self._servers[server_name]
        self._save_servers()
        return True

    def get_server(self, server_name: str) -> Optional[ServerConfig]:
        """Get a server configuration by name.

        Args:
            server_name: Name of the server

        Returns:
            ServerConfig or None if not found
        """
        return self._servers.get(server_name)

    def list_servers(self) -> Dict[str, ServerConfig]:
        """Get all servers in the global configuration.

        Returns:
            Dict mapping server names to configurations
        """
        return self._servers.copy()

    def server_exists(self, server_name: str) -> bool:
        """Check if a server exists in the global configuration.

        Args:
            server_name: Name of the server

        Returns:
            bool: True if server exists
        """
        return server_name in self._servers

    def update_server(self, server_config: ServerConfig) -> bool:
        """Update an existing server configuration.

        Args:
            server_config: Updated server configuration

        Returns:
            bool: Success or failure
        """
        if server_config.name not in self._servers:
            logger.warning(f"Server '{server_config.name}' not found for update")
            return False

        self._servers[server_config.name] = server_config
        self._save_servers()
        return True

    # Virtual Profile Methods
    def get_servers_by_profile_tag(self, profile_tag: str) -> Dict[str, ServerConfig]:
        """Get all servers that have a specific profile tag.

        Args:
            profile_tag: The profile tag to filter by

        Returns:
            Dict mapping server names to configurations that have the tag
        """
        return {name: config for name, config in self._servers.items() if config.has_profile_tag(profile_tag)}

    def add_profile_tag_to_server(self, server_name: str, profile_tag: str) -> bool:
        """Add a profile tag to a specific server.

        Args:
            server_name: Name of the server
            profile_tag: Profile tag to add

        Returns:
            bool: Success or failure
        """
        if server_name not in self._servers:
            logger.warning(f"Server '{server_name}' not found")
            return False

        self._servers[server_name].add_profile_tag(profile_tag)
        self._save_servers()
        return True

    def remove_profile_tag_from_server(self, server_name: str, profile_tag: str) -> bool:
        """Remove a profile tag from a specific server.

        Args:
            server_name: Name of the server
            profile_tag: Profile tag to remove

        Returns:
            bool: Success or failure
        """
        if server_name not in self._servers:
            logger.warning(f"Server '{server_name}' not found")
            return False

        self._servers[server_name].remove_profile_tag(profile_tag)
        self._save_servers()
        return True

    def get_all_profile_tags(self) -> List[str]:
        """Get all unique profile tags across all servers.

        Returns:
            List of unique profile tag names
        """
        all_tags = set()
        for config in self._servers.values():
            all_tags.update(config.profile_tags)
        return sorted(list(all_tags))

    def get_virtual_profiles(self) -> Dict[str, List[str]]:
        """Get all virtual profiles and their associated server names.

        Returns:
            Dict mapping profile names to lists of server names
        """
        profiles = {}
        for server_name, config in self._servers.items():
            for tag in config.profile_tags:
                if tag not in profiles:
                    profiles[tag] = []
                profiles[tag].append(server_name)
        return profiles

    def delete_virtual_profile(self, profile_tag: str) -> int:
        """Delete a virtual profile by removing the tag from all servers.

        Args:
            profile_tag: Profile tag to remove from all servers

        Returns:
            int: Number of servers that had the tag removed
        """
        count = 0
        for config in self._servers.values():
            if config.has_profile_tag(profile_tag):
                config.remove_profile_tag(profile_tag)
                count += 1

        if count > 0:
            self._save_servers()

        return count

    def virtual_profile_exists(self, profile_tag: str) -> bool:
        """Check if a virtual profile exists (has any servers with the tag).

        Args:
            profile_tag: Profile tag to check

        Returns:
            bool: True if any server has this tag
        """
        return any(config.has_profile_tag(profile_tag) for config in self._servers.values())
